#include <pthread.h>
#include <string.h>

#include "ErrCode.h"
#include "Thread.h"
#include "zmalloc.h"


#define THREAD_DYNAMIC_ENTRY	1
#define MANAGER_THREAD_NAME		"Thread Manager"

//Define it to treat the manager as a special thread
//not a running thread
#define THREAD_MANAGER_AS_SPECIAL 1


//total created threads num to be used as a magic num in making thread id
static int s_nTotalCreatedThreads = 0;

//(x|1)<<16 to make sure 0(null) will not be return 
#define MAKE_THREAD_INDEX(idx) ((((++s_nTotalCreatedThreads)|(1))<<(16))+((short)(idx)))
#define GET_THREAD_INDEX(idx) ((int)((short)((int)(idx))))

#define MAX_THREAD_ENTRY		256
#define THREAD_ENTRY_INC_STEP	32


#define THREAD_INIT_ENTRY	THREAD_ENTRY_INC_STEP


static THREAD_MANAGER s_Mgr = 
{
	0,
	NULL,
	0,
	NULL,
	PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, //can be locked recursively
	0,
	0,
	THREAD_IS_INVALID
};


#define PMGR_SYNC_LOCK(pMgr) (&(pMgr->hSyncLock))

#define LOCK_THREAD_MANAGER(pMgr)			pthread_mutex_lock(PMGR_SYNC_LOCK(pMgr))
#define UNLOCK_THRAED_MANAGER(pMgr)			pthread_mutex_unlock(PMGR_SYNC_LOCK(pMgr))
#define DESTORY_THREAD_MANAGER_LOCK(pMgr)	pthread_mutex_destory(PMGR_SYNC_LOCK(pMgr))

#define LOCK_ARG_SYNC(pArg)			pthread_mutex_lock(&((pArg)->hSyncLock))
#define UNLOCK_ARG_SYNC(pArg		pthread_mutex_unlock(&((pArg)->hSyncLock))
#define DESTROY_ARG_SYNC(pArg)		pthread_mutex_destory(&((pArg)->hSyncLock))


#define THREAD_IS_VALID(pEntry)	((pEntry)->dwThreadId!=0)

/*==========================================================================
 *FUNCTION	:	Thread_GetEntryById
 *PURPOSE	:	get the thread entry accroding to the thread handle
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:		
 *RETURN	:  	null is error 
 *=========================================================================*/
static THREAD_ENTRY *Thread_GetEntryById(ThreadManager *pThreadManager, void * hThread)
{
	if(pThreadManager==NULL||hThread==NULL)
		return NULL;

#ifdef _DEBUG_THREAD
	trace("Get entry by thread Id!");
#endif

	DWORD index = *((DWORD*)hThread);
	int nEntryIndex = GET_THREAD_INDEX(index);

	if(nEntryIndex<0||nEntryIndex>=pThreadManager->nThreadEntries)
	{
#ifdef _DEBUG_THREAD
		trace("Entry Index is error!");
#endif
		return NULL;
	}

	THREAD_ENTRY *pEntry = pThreadManager->pThreadEntries[nEntryIndex];

	if(pEntry->dwThreadId != index)
	{
#ifdef _DEBUG_THREAD
		trace("pEntry dwThreadId is not equal to nIndex!");
		return NULL;
#endif
	}
	return pEntry;

}

/*==========================================================================
 *FUNCTION	:	Thread_EnlargeEntries
 *PURPOSE	:		
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	nEntryToAdd	
 *RETURN	:  	0 is successfully , other is error 
 *=========================================================================*/
static int Thread_EnlargeEntries(THREAD_MANAGER *pThreadManager, int nEntryToAdd)
{
	THREAD_ENTRY *pNewEntries = NULL;
	int nNewEntires = pThreadManager->nThreadEntries + nEntryToAdd;

	pNewEntries = (THREAD_ENTRY *)zrealloc(pThreadManager->pThreadEntries,
		   							       sizeof(THREAD_ENTRY)*nNewEntires);

	if(pNewEntries==NULL)
	{
#ifdef _DEBUG_THREAD
		trace("out of memory to enlarge the thread manager");
		return -1;
#endif
	}

	memset((void*)&pNewEntries[pThreadManager->nThreadEntries], 0, nEntryToAdd);

	pThreadManager->nThreadEntries = nNewEntires;
	pThreadManager->pThreadEntries = pNewEntries;

	return 0;
}

/*==========================================================================
 *FUNCTION	:	Thread_GetEmptyEntry
 *PURPOSE	:	get an empty thread entry from manager	
 *CALLS		:	
 *CALL BY	:	Thread_Create
 *ARGUMENTS	:		
 *RETURN	:  	-1 for fail. other is the index of the entry
 *COMMENTS	:	the thread manager must be locked befor calling this function 
 *=========================================================================*/
static int Thread_GetEmptyEntry(Thread_Manager *pThreadManager)
{
	if(pThreadManager==NULL)
		return -1;

	THREAD_ENTRY *pEntry;
	
	if(pThreadManager->nRuningThreads>=pThreadManager->nThreadEntries)
	{
		if(Thread_EnlargeEntries(pThreadManager, THREAD_ENTRY_INC_STEP)!=0)
			return -1;
	}

	if(pThreadManager->nLastEmptyEntry >= pThreadManager->nThreadEntries)
		pThreadManager->nLastEmptyEntry = 0;

	int i = pThreadManager->nLastEmptyEntry;

	pEntry = &(pThreadManager->pThreadEntries[i]);

	while(THREAD_IS_VALID(pEntry))
	{
		i++;
		pEntry++;
		
		if(i>=pThreadManager->nThreadEntries)
		{
			i = 0;
			pEntry = &(pThreadManager->pThreadEntries[i]);
		}
	}

	pThreadManager->nLastEmptyEntry = i+1;
	pThreadManager->nRuningThreads++;

	return i;
}

/*==========================================================================
 *FUNCTION	:	Thread_InitThread
 *PURPOSE	:	init the thread arg	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:		
 *RETURN	:  	null for error 
 *=========================================================================*/
static THREAD_START_ARG *Thread_InitThread(ThreadManager *pThreadManager,
										   const char * pszThreadName,
										   THREAD_START_ARG pThreadFunc,
										   void *pThreadArg,
										   DWORD *pdwExitCode,
										   DWORD dwCreateFlag)
{
	if(pThreadFunc == NULL)
	{
#ifdef _DEBUG_THREAD
		trace("the pThreadFunc is null.");
#endif
		return NULL;
	}

	int nEntryId;
	THREAD_START_ARG *pArg;
	THREAD_ENTRY *pEntry;
	
	pEntryId = Thread_GetEmptyEntry();
	if(pEntryId<0)
	{
#ifdef	_DEBUG_THREAD
		trace("get empty entry address error");
#endif
		return NULL;
	}	

	pArg = (THREAD_START_ARG*)zmalloc(sizeof(THREAD_START_ARG));
	if(pArg==NULL)
	{
#ifdef _DEBUG_THREAD
	   trace("out of memmory on create args.");	
#endif
	   return NULL;
	}
	
	pEntry = &pThreadManager->pThreadEntries[nEntryId];

	if(THREAD_FLAG_HAS(dwCreateFlag, THREAD_FLAG_HAS_MSG_QUEUE))
	{
	}

	pEntry->pMsgQueue = NULL;

	if(pszThreadName == NULL || *pszThreadName == '\0')
		pszThreadName = "__NO_NAME__";
	
	strncpy(pEntry->szThreadName, pszThreadName, sizeof(pEntry->szThreadName)-1);
	pEntry->szThreadName[LEN_THREAD_NAME-1] = '\0';

	pEntry->dwThreadHeartBeat = THREAD_INIT_HEARTBEATS;
	pEntry->dwThreadId = MAKE_THREAD_INDEX(nEntryId);

	pEntry->nStatus = THREAD_IS_RUNNING;

	pArg->hSyncLock = PTHREAD_MUTEX_INITIALIZER;

	pArg->pThreadEntry = pEntry;
	pArg->hThread = (void*)&(pEntry->dwThreadId);
	pArg->pdwExitCode = pdwExitCode;
	pArg->pThreadFunc = pThreadFunc;
	pArg->pThreadArg = pThreadArg; 
	 
	return pArg;
}


static int Thread_CancelThreads(RUN_THREAD_ENTRY *pEntry, int nEntry)
{
	if(pEntry==NULL)
		return ERR_THREAD_KILLED;

	
}

/*==========================================================================
 *FUNCTION	:	Thread_Create	
 *PURPOSE	:	create a detach a worker thread	
 *CALLS		:	pthread API	
 *CALL BY	:
 *ARGUMENTS	:	Thread_Manager : pHandlerFunc	
 				pThreadManager
 *RETURN	:  	ERR_OK if OK, else ERR_THREAD_INIT_MANAGER for error 
 *=========================================================================*/
void * Thread_Create(ThreadManager *pThreadManager,
					 const char *pThreadName,
					 THREAD_START_FUNC pThreadFunc,
					 void *pThreadArg,
					 DWORD *pdwExitCode,
					 DWORD dwCreateFlag)
{
	THREAD_START_ARG *pArg = NULL;

#ifdef _DEBUG_THREAD
	trace("create a thread!");
#endif
	LOCK_THREAD_MANAGER(pThreadManager);

	pArg = Thread_InitThread(pThreadName, pThreadFunc, pThreadArg, pdwExitCode, dwCreateFlag);

	if(pArg!=NULL)
	{
		THREAD_ENTRY *pEntry = NULL;
		unsigned int threadId = (unsigned int)*((DWORD*)pArg->hThread);
#ifdef	_DEBUG_THREAD
		printf("[%s] -- nThread Id first [%u]\n", __FUNCTION__, threadId);
#endif	
		
		threadId = GET_THREAD_INDEX(threadId);
#ifdef _DEBUG_THREAD
		printf("[%s] -- nThread Id second [%u]\n", __FUNCTION__< threadId);
#endif
		pEntry = &pThreadManager->pThreadEntries[threadId];
		LOCK_ARG_SYNC(pArg);

		if(ptread_create(&pEntry->hSystemThread, 
						 NULL, 
						 (PTHREAD_START_ROUTE)Thread_HookEntry,
						 (void*)pArg)==0)

		{
			pthread_detach(pEntry->hSystemThread);
#ifdef _DEBUG_THREAD
			printf("[%s] -- the thread ID-SYS:[%d], APP-ID:[%d:%d],NAME:[%s]\n",
					__FUNCTION__,
					(int)pEntry->hSystemThread,
					(int)pEntry->dwThreadId,
					*(DWORD*)threadId,
					pThreadName);
#endif
			UNLOCK_ARG_SYNC(pArg);
		}
		else
		{
#ifdef _DEBUG_THREAD
			printf("[%s] -- fails on creating thread %s.\n", );
#endif
			Thread_ReleaseEntry(pEntry);
		}
		
	}
}



/*==========================================================================
 *FUNCTION	:	Thread_ManagerInit
 *PURPOSE	:	init thread manager	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	THREAD_EVENT_HANDLER : pHandlerFunc	
 				pThreadManager
 *RETURN	:  	ERR_OK if OK, else ERR_THREAD_INIT_MANAGER for error 
 *=========================================================================*/
int Thread_ManagerInit(THREAD_MANAGER *pThreadManager,
					   THREAD_EVENT_HANDLER *pHandlerFunc)
{
#ifdef _DEBUG_THREAD
	trace("Run thread manager starting....");
#endif

	if(pEventFunc==NULL)
	{
#ifdef _DEBUG_THREAD
		trace("invalid event handler function.");
#endif
		return ERR_THREAD_INIT_MANAGER;

	}

	pThreadManager->pThreadEventHandlerFunc = pEventFunc;

	if(!Thread_EnlargeEntries(THREAD_INIT_ENTRY))
	{
#ifdef _DEBUG_THREAD
		trace("fail  on init thread entries.");
#endif 
		return ERR_THREAD_INIT_MANAGER;
	}

	if(pthread_create(&(pThreadManager->hManagerThread), 
					  NULL, 
					  (PTHREAD_START_ROUTE)Thread_Manager,
					  (void*)pThreadManager)!=0)
	{
#ifdef _DEBUG_THREAD
		trace("fail to create thread manager thread");
		pThreadManager->nStatus = THREAD_IS_INVALID;
		return ERR_THREAD_INIT_MANAGER;
#endif
	}
	pThreadManager->nStatus = THREAD_IS_RUNNING;

	pthread_detach(pThreadManager->hManagerThread);
	return ERR_THREAD_OK;
}

/*==========================================================================
 *FUNCTION	:	Thread_ManagerExit
 *PURPOSE	:	exit thread manager	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:		
 *RETURN	:  	ERR_THREAD_OK if OK, ERR_THREAD_STILL_RUNNING for thread does
				not stopped, ERR_THREAD_KILLED for thread is terminated by 
			    force	
 *=========================================================================*/
int Thread_ManagerExit(THREAD_MANAGER *pThreadManager,
					   int nTimeToWaitThreadQuit,
					   int killTimeoutThread)
{
	if(pThreadManager==NULL)
		return ERR_THREAD_OK;
	
	pThreadManager->nStatus = THREAD_TO_QUIT;

	pThreadManager->pEventFunc(THREAD_EVENT_HEARTBEAT, NULL, MANAGER_THREAD_NAME); 

	int nResult = Thread_
	

}



/*==========================================================================
 *FUNCTION	:	Thread_PostMessage
 *PURPOSE	:	post a message to given thread
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	 
 *RETURN	:	ERR_OK for post a msg successfully, ERR_THREAD_INVALID_ID 
 				for an invalid hThread pass in. ERR_THREAD_MSG_FULL for msg
				queue is full
 *=========================================================================*/
int Thread_PostMessage(void * hThread,
					   THREAD_MSG * pMsg,
					   int urgent)
{
}


/*==========================================================================
 *FUNCTION	:	Thread_PostQuitMessage
 *PURPOSE	:	post a message to given thread
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread	: -1 for all threads	 
 *RETURN	:
 *=========================================================================*/
int Thread_PostQuitMessage(void * hThread)
{
}


/*==========================================================================
 *FUNCTION	:	Thread_Stop
 *PURPOSE	:	stop a thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread	: thread id
				nTimeToWaitThreadQuit : wait n ms on thread to quit
				killTimeoutedThread	  : if timeout , kill it
 *RETURN	:   ERR_THREAD_STILL_RUNNING for thread does not stopped,
 				ERR_THREAD_KILLED for thread is terminated by force
 *=========================================================================*/
int Thread_Stop(void * hThread,
				int nTimeToWaitThreadQuit,
				int killTimeoutedThread)
{
}




/*=========================================================================
 *FUNCTION	:	Thread_GetMessage
 *PURPOSE	:	Get a message from a running thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread : null to get self name
 				pMsg	: store the msg
				nPeek	: not zero is peek only
				deTimeout : if no msg, the time is ms will wait
 *RETURN	:	ERR_OK for get a msg, ERR_THREAD_INVALID_ID for an invalid 
 				hThread pass in. ERR_THREAD_MSG_EMPTY for no msg
 *=========================================================================*/
int Thread_GetMessage(void * hThread, 
					  THREAD_MSG *pMsg, 
					  int nPeek, 
					  DWORD dwTimeout)
{
}



/*=========================================================================
 *FUNCTION	:	Thread_GetStatus
 *PURPOSE	:	Get the running state of a thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	hThread : 
 *RETURN	:	thread status 
 *=========================================================================*/
int Thread_GetStatus(void * hThread)
{
}


/*==========================================================================
 *FUNCTION	:	Thread_GetThreadCount
 *PURPOSE	:	Get the running state of a thread	
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	 
 *RETURN	:	the thread count 
 *=========================================================================*/
int Thread_GetThreadCount(void)
{
}


/*==========================================================================
 *FUNCTION	:	Thread_HeartBeat
 *PURPOSE	:	to trigger atime of heartbeat. a thread would call this func
 *CALLS		:	
 *CALL BY	:
 *ARGUMENTS	:	 
 *RETURN	:	the current heartbeat count 
 *=========================================================================*/
int Thread_HeartBeat(void * hThread)
{
}














